/**
 * <pre>
 * Title: 		RemotePersistServiceImpl.java
 * Author:		linriqing
 * Create:	 	2012-3-9 下午04:22:25
 * Copyright: 	Copyright (c) 2012
 * Company:		Shenzhen Helper
 * <pre>
 */
package com.hengpeng.itfinoss.service.impl;

import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.hengpeng.common.persist.QueryParameter;
import com.hengpeng.common.persist.QueryResult;
import com.hengpeng.common.persist.entity.AbstractEntity;
import com.hengpeng.common.persist.query.DynamicQuery;
import com.hengpeng.common.persist.query.Projections;
import com.hengpeng.common.util.StringHelper;
import com.hengpeng.itfinoss.service.PersistService;
import com.hengpeng.itfinoss.service.ServiceFactory;
import com.hengpeng.itfinoss.util.ConfigUtil;
import com.hengpeng.itfinoss.util.DigestAuthUtils;

/**
 * <pre>
 * 远程持久层接口实现
 * </pre>
 * @author linriqing
 * @version 1.0, 2012-3-9
 */
@Service("remotePersistServiceImpl")
@Lazy
public class RemotePersistServiceImpl implements PersistService
{
	public static final String JSON_DATETIME_FORMAT = "yyyyMMddHHmmss";

	private static final String DigestAuth_ClientId = "admin";

	private static final String DigestAuth_ClientPwd = "admin";

	private static final String DigestAuth_Key = "acegi";

	private static final String DigestAuth_RealName = "Contacts Realm via Digest Authentication";

	private static final String RemoteServiceUrl = ConfigUtil.getConfigValue("remote.service.url")
			+ "/RemotePersistService/";

	private static final Log logger = LogFactory.getLog(RemotePersistServiceImpl.class);

	GsonBuilder builder = createGson();

	public static GsonBuilder createGson()
	{
		GsonBuilder gsonBuilder = new GsonBuilder();
		gsonBuilder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>()
		{
			@Override
			public Date deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
					throws JsonParseException
			{
				try
				{
					SimpleDateFormat sdf = new SimpleDateFormat(JSON_DATETIME_FORMAT);
					return sdf.parse(json.getAsString());
				}
				catch (ParseException e)
				{
					throw new RuntimeException("日期格式不对,Pattern应该为:" + JSON_DATETIME_FORMAT, e);
				}
			}
		});
		gsonBuilder.registerTypeAdapter(Date.class, new JsonSerializer<Date>()
		{
			@Override
			public JsonElement serialize(Date arg0, Type arg1, JsonSerializationContext arg2)
			{
				SimpleDateFormat sdf = new SimpleDateFormat(JSON_DATETIME_FORMAT);
				return new JsonPrimitive(sdf.format(arg0));
			}
		});
		return gsonBuilder;
	}

	@Autowired
	private ServiceFactory serviceFactory;

	public <T> T doPostTrans(String transName, Class<T> returnType, Object parameter, Object... pathValue)
	{
		try
		{
			String url = RemoteServiceUrl + transName;
			HttpEntity<Object> entity = new HttpEntity<Object>(parameter, DigestAuthUtils.createAuthHeaders(url,
					HttpMethod.POST.name(), DigestAuth_ClientId, DigestAuth_RealName, DigestAuth_ClientPwd,
					DigestAuth_Key));
			return (T) serviceFactory.getRestTemplate().postForEntity(url, entity, returnType, pathValue).getBody();
		}
		catch (RestClientException e)
		{
			Gson gson = builder.create();
			if (parameter.getClass().isAssignableFrom(QueryParameter.class))
			{
				QueryParameter<?> queryParameter = (QueryParameter<?>) parameter;
				List<Object> parameters = Arrays.asList(queryParameter.getParameters());
				logger.error(
						"调用远程服务{" + transName + "}异常, 数据{customQuery:{"
								+ queryParameter.getCustomQuery().getSqlResult().getSql() + "}, type:"
								+ queryParameter.getType() + ", parameters:" + parameters + "}", e);
			}
			else
			{
				logger.error("调用远程服务{" + transName + "}异常, 数据{" + gson.toJson(parameter) + "}", e);
			}
			gson = null;
			throw e;
		}
	}

	@Override
	public void delete(AbstractEntity entity)
	{
		this.doPostTrans("delete", null, entity);
	}

	@Override
	public <T extends AbstractEntity> void delete(Class<T> type, Object id)
	{
		QueryParameter<T> queryParameters = new QueryParameter<T>();
		queryParameters.setType(type);
		queryParameters.addParameter(id);
		this.doPostTrans("deleteById", null, queryParameters);
	}

	@Override
	public <T extends AbstractEntity> T get(Class<T> type, Object id)
	{
		QueryParameter<T> queryParameters = new QueryParameter<T>();
		queryParameters.setType(type);
		queryParameters.addParameter(id);
		return this.doPostTrans("get", type, queryParameters);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends AbstractEntity> List<T> list(Class<T> type)
	{
		return this.doPostTrans("list", List.class, type);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends AbstractEntity> T save(T entity)
	{
		Class<T> type = (Class<T>) entity.getClass();
		return this.doPostTrans("save", type, entity);
	}

	@Override
	public void saveAllObject(Collection<? extends AbstractEntity> entitys)
	{
		this.doPostTrans("saveAllObject", null, entitys);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends AbstractEntity> T update(T entity)
	{
		Class<T> type = (Class<T>) entity.getClass();
		return this.doPostTrans("update", type, entity);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends AbstractEntity> List<T> find(Class<T> type, DynamicQuery query)
	{
		QueryParameter<T> queryParameters = new QueryParameter<T>();
		queryParameters.setType(type);
		queryParameters.setCustomQuery(query);
		QueryResult<T> doPostTrans = this.doPostTrans("find", QueryResult.class, queryParameters);
		return doPostTrans.getResults();
	}

	public Long count(DynamicQuery query)
	{
		List<?> obj = findObject(null, query);
		return Long.valueOf(obj.get(0) == null ? "0" : obj.get(0).toString());
	}

	@Override
	public <T extends AbstractEntity> Long findPageCount(DynamicQuery query, String property)
	{
		if (StringHelper.isEmpty(property))
		{
			query.addProjection(Projections.count());
		}
		else
		{
			query.addProjection(Projections.count(property));
		}
		List<Object> result = findObject(null, query);
		return Long.valueOf(result.get(0) == null ? "0" : result.get(0).toString());
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends AbstractEntity> QueryResult<T> findWithPage(Class<T> type, DynamicQuery query)
	{
		QueryParameter<T> queryParameters = new QueryParameter<T>();
		queryParameters.setType(type);
		queryParameters.setCustomQuery(query);
		return this.doPostTrans("find", QueryResult.class, queryParameters);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends AbstractEntity> List<Object> findObject(Class<T> type, DynamicQuery query)
	{
		QueryParameter<T> queryParameters = new QueryParameter<T>();
		queryParameters.setType(type);
		queryParameters.setCustomQuery(query);
		QueryResult<?> doPostTrans = this.doPostTrans("find", QueryResult.class, queryParameters);
		return (List<Object>) doPostTrans.getResults();
	}

}
